#if 0 
/dts-v1/;

/ {
    model = "My Virtual Device Example";
    compatible = "my-virtual-device-from-dev-tree";

    my_virtual_device {
        compatible = "my-virtual-device";
        status = "okay";
        example-string = "Hello, World!";
        example-number = <123>;
    };
};
#endif

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/uaccess.h>
#include <linux/platform_device.h>


#define DEVICE_NAME "my_virtual_device_from_dt"
#define CLASS_NAME  "my_virtual_device_class"
#define DEVICE_NAME_IN_DRIVER "my_virtual_device"

static int major = -1;
static int minor = 0;
#define DEVICE_MINOR_FOR_DTNODE 0
#define DEVICE_MINOR_FOR_CREATED_BY_NAME 1
static  dev_t dev_n ;


static struct class *my_device_class=NULL;
//static struct cdev my_device_cdev;

static struct device_node *my_device_node=NULL;
static const char *example_string="device from name";
static int example_number=101;

static int my_device_open(struct inode *inode, struct file *file) {
    printk(KERN_INFO "my_virtual_device: Device opened\n");
    return 0;
}

static int my_device_release(struct inode *inode, struct file *file) {
    printk(KERN_INFO "my_virtual_device: Device closed\n");
    return 0;
}

static ssize_t my_device_read(struct file *file, char __user *buf, size_t count, loff_t *pos) 
{
    char buffer[256];
    int len;

    // 将设备树中的属性值写入缓冲区
    len = snprintf(buffer, sizeof(buffer), 
                   "example-string: %s\n"
                   "example-number: %d\n", 
                   example_string, example_number)-*pos;

	printk("HanJ %s:count=%d len=%d\n" , __func__ , count , len ) ;
	if(len <= 0 )
		return 0 ;
    if (len > count) {
        len = count;
    }

    if (copy_to_user(buf, buffer, len)) {
		printk("HanJ error to copy_to_user\n") ;
        return -EFAULT;
    }
	*pos += len ;

    return len;
}

static struct file_operations fops = {
    .open = my_device_open,
    .release = my_device_release,
    .read = my_device_read,
};

static struct cdev cdev_my_virt;
static int probeCallTimes = 0 ;
static int  my_device_probe(struct platform_device *pdev) {
	int ret ;
	char* my_virtual_dev_name;
    printk(KERN_INFO "my_virtual_device(%s): Probe called \n", pdev->name);

    // 获取设备树节点
    my_device_node = pdev->dev.of_node;
	if( !my_device_node ){
		my_virtual_dev_name = DEVICE_NAME_IN_DRIVER"C" ;
		printk("HanJ,Not a device-tree device\n") ;
		//return 0 ;
	}else {
		my_virtual_dev_name =  DEVICE_NAME"C" ;
	    // 从设备树中读取属性
	    of_property_read_string(my_device_node, "example-string", &example_string);
	    of_property_read_u32(my_device_node, "example-number", &example_number);

	    printk(KERN_INFO "my_virtual_device: example-string = %s\n", example_string);
	    printk(KERN_INFO "my_virtual_device: example-number = %d\n", example_number);
	}

	if( major == -1 ){
	    // 注册字符设备
	    ret = alloc_chrdev_region(&dev_n, 0, 2,DEVICE_NAME_IN_DRIVER) ;
		if( ret < 0 ) {
	        printk(KERN_ERR "my_virtual_device: Failed to register character device\n");
	        return 0;
	    }else {
			printk(KERN_ERR "alloc_chrdev_region ok\n") ;
	    }
		major = MAJOR(dev_n);
		minor = MINOR(dev_n);
		printk("mymotor major is %d, minor is %d \n", major, minor);
		//initial cdev
		cdev_my_virt.owner = THIS_MODULE;
		cdev_init(&cdev_my_virt,&fops);
		//add cdev
		cdev_add(&cdev_my_virt,dev_n,2);
	
		//major = register_chrdev(0, DEVICE_NAME, &fops);
	    my_device_class = class_create(THIS_MODULE, CLASS_NAME);
	    if (IS_ERR(my_device_class)) {
	        unregister_chrdev(major, DEVICE_NAME);
	        printk(KERN_ERR "my_virtual_device: Failed to create class\n");
	        return PTR_ERR(my_device_class);
	    }
		//minor = DEVICE_MINOR_FOR_DTNODE ;
		my_virtual_dev_name = DEVICE_NAME"C" ; 
	}else {
		minor++ ;// = DEVICE_MINOR_FOR_CREATED_BY_NAME;
		my_virtual_dev_name = DEVICE_NAME_IN_DRIVER"C" ;
	}	

    device_create(my_device_class, NULL, MKDEV(major, minor), NULL, my_virtual_dev_name );
	probeCallTimes ++ ;
    printk(KERN_INFO "my_virtual_device: Device registered with major number %d\n", major);
    return 0;
}

#define PRT printk("HanJ %s %s %d\n" ,__FILE__ , __func__ ,__LINE__ ) 
static int  my_device_remove(struct platform_device *pdev) {
	int mi;
    PRT;printk(KERN_INFO "my_virtual_device: Remove called\n");
	probeCallTimes -- ;
	if( probeCallTimes )
		return 0 ;
	PRT;
	cdev_del(&cdev_my_virt) ;
	PRT;PRT;
	unregister_chrdev_region( dev_n , 2 );
	PRT;PRT;
	for( mi = 0 ; mi <= minor ; mi++){
		device_destroy(my_device_class, MKDEV(major, mi));
		PRT;PRT;
	}
    class_destroy(my_device_class);
	PRT;PRT;
    unregister_chrdev(major, DEVICE_NAME);
	PRT;PRT;
    return 0;
}

static const struct of_device_id my_device_of_match[] = {
    { .compatible = "my-virtual-device-from-dev-tree" },
    { /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, my_device_of_match);

static struct platform_driver my_device_driver = {
    .probe = my_device_probe,
    .remove = my_device_remove,
    .driver = {
        .name = DEVICE_NAME_IN_DRIVER,
        .of_match_table = my_device_of_match,
    },
};

module_platform_driver(my_device_driver);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple virtual device driver using Device Tree");
MODULE_VERSION("0.1");

